package com.michaelbulava.TFS.vcs.internal.providers;

import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vcs.AbstractVcsHelper;
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.changes.ContentRevision;
import com.intellij.openapi.vcs.diff.DiffProvider;
import com.intellij.openapi.vcs.diff.ItemLatestState;
import com.intellij.openapi.vcs.history.VcsRevisionNumber;
import com.intellij.openapi.vfs.VirtualFile;
import com.michaelbulava.TFS.log.FileLogger;
import com.michaelbulava.TFS.vc.tfsitem.TFSFile;
import com.michaelbulava.TFS.vcs.TFSVcs;
import com.michaelbulava.TFS.vcs.exceptions.NotConnectedToTFS;
import com.michaelbulava.TFS.vcs.exceptions.TFSException;
import com.michaelbulava.TFS.vcs.internal.TFSFiles.TFSFilePath;
import com.michaelbulava.TFS.vcs.revision.TFSContentRevision;
import com.michaelbulava.TFS.vcs.utils.TFSFileUtil;
import com.microsoft.tfs.core.clients.versioncontrol.GetItemsOptions;
import com.microsoft.tfs.core.clients.versioncontrol.soapextensions.*;
import com.microsoft.tfs.core.clients.versioncontrol.specs.version.LatestVersionSpec;
import org.jetbrains.annotations.Nullable;

import java.util.Arrays;
import java.util.Collections;
import java.util.Map;

/**
 * Created by MichaelA on 8/19/2015.
 */
public class TFSDiffProvider implements DiffProvider {
    private static final Logger log = FileLogger.getInstance(TFSDiffProvider.class);
    private final Project myProject;

    public TFSDiffProvider(Project project) {
        myProject = project;
    }

    @Nullable
    @Override
    public VcsRevisionNumber getCurrentRevision(VirtualFile virtualFile) {
        FilePath path = TFSFileUtil.getFilePath(virtualFile);
        Workspace workspace = null;
        try {
            workspace = TFSVcs.getInstance(myProject).getWorkspaceForFile(path);
        } catch (NotConnectedToTFS e) {
            return VcsRevisionNumber.NULL;
        }
        Map<FilePath, ExtendedItem> extendedItemMap = TFSFileUtil.getFilePathExtendedItemMap(myProject, workspace,
                Arrays.asList(new FilePath[] { path }));
        if (extendedItemMap == null || extendedItemMap.isEmpty())
            return VcsRevisionNumber.NULL;
        return new VcsRevisionNumber.Int(extendedItemMap.get(path).getLocalVersion());
    }

    @Nullable
    @Override
    public ItemLatestState getLastRevision(VirtualFile virtualFile) {
        FilePath localPath = TFSFileUtil.getFilePath(virtualFile);
        return getLastRevision(localPath);
    }

    @Nullable
    @Override
    public ItemLatestState getLastRevision(FilePath filePath) {
        if (filePath instanceof TFSFilePath){
            VcsRevisionNumber.Int revisionNumber = new VcsRevisionNumber.Int(((TFSFilePath) filePath).getLatestVersion());
            return new ItemLatestState(revisionNumber, filePath.getIOFile().exists(), false);
        } else {
            try{
                Workspace workspace = TFSVcs.getInstance(myProject).getWorkspaceForFile(filePath);
                if (workspace == null)
                    return new ItemLatestState(VcsRevisionNumber.NULL, false, false);

                Map<FilePath, ExtendedItem> extendedItemMap = TFSFileUtil.getFileExtendedItems(myProject, workspace,
                        Arrays.asList( new FilePath[] { filePath}), DeletedState.ANY, GetItemsOptions.NONE);

                if (extendedItemMap == null || extendedItemMap.isEmpty())
                    return new ItemLatestState(VcsRevisionNumber.NULL, false, false);

                ExtendedItem extendedItem = extendedItemMap.get(filePath);

                Item item = workspace.getClient().getItem(extendedItem.getTargetServerItem(), LatestVersionSpec.INSTANCE);
                if (item != null){
                    VcsRevisionNumber.Int revisionNumber = new VcsRevisionNumber.Int(item.getChangeSetID());
                    return new ItemLatestState(revisionNumber, item.getDeletionID() != 0, false);
                }
                return new ItemLatestState(VcsRevisionNumber.NULL, false, false);
            } catch(Throwable tr){
                AbstractVcsHelper.getInstance(myProject).showError(new VcsException(tr.getMessage(), tr),
                        TFSVcs.VCS_NAME);
            }
            return new ItemLatestState(VcsRevisionNumber.NULL, false, false);
        }
    }

    @Nullable
    @Override
    public ContentRevision createFileContent(VcsRevisionNumber vcsRevisionNumber, VirtualFile virtualFile) {

        if (VcsRevisionNumber.NULL.equals(vcsRevisionNumber))
            return null;
        FilePath path = TFSFileUtil.getFilePath(virtualFile);
        try{
//            Workspace workspace = TFSVcs.getInstance(myProject).getWorkspaceForFile(path);
//            if (workspace == null)
//                return null;
//            Map<FilePath, ExtendedItem> extendedItemMap = TFSFileUtil.getFilePathExtendedItemMap(myProject, workspace,
//                    Arrays.asList(new FilePath[]{path}));
//            if (extendedItemMap == null || extendedItemMap.isEmpty())
//                return null;
//            ExtendedItem extendedItem = extendedItemMap.get(path);
//
            return TFSContentRevision.create(myProject, path, Integer.getInteger(vcsRevisionNumber.asString()) );
        } catch (TFSException e) {
            AbstractVcsHelper.getInstance(this.myProject).showError(new VcsException(e), TFSVcs.VCS_NAME);
        }
        return null;
    }

    @Nullable
    @Override
    public VcsRevisionNumber getLatestCommittedRevision(VirtualFile virtualFile) {
        FilePath file = TFSFileUtil.getFilePath(virtualFile);
        if (file instanceof TFSFilePath){
            return new VcsRevisionNumber.Int(((TFSFilePath) file).getLatestVersion());
        } else {
            log.warn("I need to handle this?");
            return VcsRevisionNumber.NULL;
        }
    }
}
